/*
 *******************************************************************************
 *
 * Copyright (C) 2019-2020 Dialog Semiconductor.
 * This computer program includes Confidential, Proprietary Information
 * of Dialog Semiconductor. All Rights Reserved.
 *
 *******************************************************************************
 */

package com.dialog.suotalib.suota;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;

import com.dialog.suotalib.global.SuotaLibConfig;
import com.dialog.suotalib.global.SuotaLibLog;
import com.dialog.suotalib.global.SuotaProfile;
import com.dialog.suotalib.ring.RingPythonManagement;
import com.dialog.suotalib.utils.MainThread;
import com.dialog.suotalib.utils.StringUtils;
import com.dialog.suotalib.utils.SuotaUtil;

import androidx.annotation.NonNull;

import static android.bluetooth.BluetoothGatt.GATT_SUCCESS;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
import static com.dialog.suotalib.global.SuotaProfile.SuotaManagerStatus.CONNECTED;
import static com.dialog.suotalib.global.SuotaProfile.SuotaManagerStatus.DISCONNECTED;
import static com.dialog.suotalib.global.SuotaProfile.Uuid.CHARACTERISTIC_DEF_SVC1_TX_UUID_128;

class GattCallback extends BluetoothGattCallback implements Handler.Callback {

    private static final String TAG = "GattCallback";

    private static final int ON_CONNECTION = 0;
    private static final int ON_DISCONNECTION = 1;
    private static final int ON_SERVICES_DISCOVERED = 2;
    private static final int ON_MTU_CHANGED = 3;
    /**
     * 读取特征
     */
    private static final int ON_CHARACTERISTIC_READ = 4;
    /**
     * 写特性
     */
    private static final int ON_CHARACTERISTIC_WRITE = 5;
    private static final int ON_CHARACTERISTIC_CHANGED = 6;
    private static final int ON_DESCRIPTOR_WRITE = 7;

    private static class Notification {

        BluetoothGattCharacteristic characteristic;
        byte[] value;

        Notification(BluetoothGattCharacteristic characteristic, byte[] value) {
            this.characteristic = characteristic;
            this.value = value.clone();
        }
    }

    private SuotaManager suotaManager;
    private HandlerThread handlerThread;
    private Handler handler;

    public GattCallback(@NonNull SuotaManager suotaManager) {
        this.suotaManager = suotaManager;
        if (!SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) {
            handlerThread = new HandlerThread(GattCallback.class.getSimpleName());
            handlerThread.start();
            handler = new Handler(handlerThread.getLooper(), this);
        }
    }

    public void destroy() {
        Log.d(TAG, "Destroy");
        if (!SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) {
            handler.removeCallbacksAndMessages(null);
            handlerThread.quit();
        }
    }

    /**
     * GATT客户端连接或断开到远程的时候。
     *
     * @param gatt     GATT客户端
     * @param status   连接或者断开操作时的状态。
     *                 {BluetoothGatt#GATT_SUCCESS} 如果操作成功。
     * @param newState 返回新的连接状态。{BluetoothProfile#STATE_DISCONNECTED}或者
     *                 {BluetoothProfile#STATE_CONNECTED}
     */
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        if (SuotaLibLog.GATT_OPERATION)
            Log.d(TAG, "onConnectionStateChange: " + newState + " status=" + status);

        if (suotaManager.getGatt() == null) {
            suotaManager.setGatt(gatt);
        }

        if (newState == STATE_CONNECTED) {  //链接
            Log.d(TAG, "Connected");
            if (SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) {
                onConnection(gatt);
            } else {
                handler.obtainMessage(ON_CONNECTION, gatt).sendToTarget();
            }
        } else {  //断开链接
            Log.d(TAG, "Disconnected, reason=" + status);
            if (SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) {
                onDisconnection();
            } else {
                handler.obtainMessage(ON_DISCONNECTION).sendToTarget();
            }
        }
    }

    /**
     * 发现服务回调
     *
     * @param gatt   调用了{BluetoothGatt#discoverServices}的GATT客户端
     * @param status 如果远程设备已经成功探索，状态为{BluetoothGatt#GATT_SUCCESS}
     */
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == GATT_SUCCESS) {
            Log.d(TAG, "Services discovered");
            if (SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) {
                onServicesDiscovered(gatt);
            } else {
                handler.obtainMessage(ON_SERVICES_DISCOVERED, gatt).sendToTarget();
            }
        } else {
            Log.e(TAG, "Service discovery failure, status=" + status);
            notifyFailure(SuotaProfile.Errors.SERVICE_DISCOVERY_ERROR);
        }
    }

    /**
     * MTU改变回调
     *
     * @param gatt
     * @param mtu
     * @param status
     */
    @Override
    public void onMtuChanged(BluetoothGatt gatt, final int mtu, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            Log.d(TAG, "MTU changed to " + mtu);
            if (SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) { //默认false
                onMtuChanged(mtu);  //计算组块大小
            } else {
                handler.obtainMessage(ON_MTU_CHANGED, mtu).sendToTarget();
            }
        } else {
            Log.e(TAG, "MTU request failure, status=" + status);
            notifyFailure(SuotaProfile.Errors.MTU_REQUEST_FAILED);
        }
    }

    /**
     * 读取特征回调
     *
     * @param gatt           调用了{BluetoothGatt#readCharacteristic}的GATT客户端
     * @param characteristic 从关联的远程设备读取的 Characteristic
     * @param status         如果读取操作成功完成，状态为{BluetoothGatt#GATT_SUCCESS}
     */
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        Log.d(TAG, "onCharacteristicRead: " + characteristic.getUuid() + " " + SuotaUtil.hexArray(characteristic.getValue()));
        if (status == GATT_SUCCESS) {
            if (SuotaLibLog.GATT_OPERATION)
                Log.d(TAG, "onCharacteristicRead: " + characteristic.getUuid() + " " + SuotaUtil.hexArray(characteristic.getValue()));
            if (SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) {
                onCharacteristicRead(characteristic);
            } else {
                handler.obtainMessage(ON_CHARACTERISTIC_READ, characteristic).sendToTarget();
            }
        } else {
            Log.e(TAG, "Failed to read characteristic: " + characteristic.getUuid() + " status=" + status);
            notifyFailure(SuotaProfile.Errors.GATT_OPERATION_ERROR);
        }
    }

    /**
     * 写入操作
     *
     * @param gatt
     * @param characteristic
     * @param status
     */
    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        Log.d(TAG, "onCharacteristicWrite: " + characteristic.getUuid() + " " + SuotaUtil.hexArray(characteristic.getValue()));
        if (status == GATT_SUCCESS) { //4
//            if (SuotaLibLog.GATT_OPERATION)
//                Log.d(TAG, "onCharacteristicWrite: " + characteristic.getUuid());
            if (SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) {
                onCharacteristicWrite(characteristic);
            } else {
                handler.obtainMessage(ON_CHARACTERISTIC_WRITE, characteristic).sendToTarget();
            }
        } else {
            Log.e(TAG, "Failed to write characteristic: " + characteristic.getUuid() + " status=" + status);
            if (!suotaManager.isRebootSent())
                notifyFailure(SuotaProfile.Errors.GATT_OPERATION_ERROR);
        }
    }

    /**
     * 特性改变回调
     *
     * @param gatt
     * @param characteristic
     */
    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        Log.d(TAG, "onCharacteristicChanged: " + characteristic.getUuid() + " " + SuotaUtil.hexArray(characteristic.getValue()));
//        suotaManager.onPythonData(SuotaUtil.hexArray(characteristic.getValue()));
        if (characteristic.getUuid().toString().equals(CHARACTERISTIC_DEF_SVC1_TX_UUID_128.toString())) {
            if (characteristic.getValue().length < 12) {
                hexArrayModel(SuotaUtil.hexArray(characteristic.getValue(), false));
                return;
            } else {
                if (suotaManager != null) {
                    suotaManager.onPythonData(hexArrayXandZhongli(SuotaUtil.hexArray(characteristic.getValue(), false)));
//                    suotaManager.onPythonData(SuotaUtil.hexArray(characteristic.getValue()));
                }
            }
        }
    }
//        Notification notification = new Notification(characteristic, characteristic.getValue());
//        if (SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) { //false
//            onCharacteristicChanged(notification);
//        } else {
//            handler.obtainMessage(ON_CHARACTERISTIC_CHANGED, notification).sendToTarget();
//        }

    /**
     * 描述写入回调
     *
     * @param gatt
     * @param descriptor
     * @param status
     */
    @Override
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        Log.e(TAG, "Failed to write descriptor: " + descriptor.getCharacteristic().getUuid() + " " + descriptor.getUuid() + " status=" + status);
        Log.e(TAG, "Value: " + SuotaUtil.hexArray(descriptor.getValue()));
        if (status == GATT_SUCCESS) {
            if (SuotaLibLog.GATT_OPERATION)
                Log.d(TAG, "onDescriptorWrite: " + descriptor.getCharacteristic().getUuid() + " " + descriptor.getUuid());
            if (SuotaLibConfig.GATT_CALLBACK_USE_BINDER_THREAD) {
                onDescriptorWrite(descriptor);
            } else {
                handler.obtainMessage(ON_DESCRIPTOR_WRITE, descriptor).sendToTarget();
            }
        } else {
            Log.e(TAG, "Failed to write descriptor: " + descriptor.getCharacteristic().getUuid() + " " + descriptor.getUuid() + " status=" + status);

        }
    }

    private void notifyFailure(final int value) {
        MainThread.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                suotaManager.getSuotaManagerCallback().onFailure(value);
            }
        });
    }

    private void notifyConnectionStateChanged(final SuotaProfile.SuotaManagerStatus status) {
        MainThread.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                suotaManager.getSuotaManagerCallback().onConnectionStateChange(status);
            }
        });
    }

    @Override
    public boolean handleMessage(Message message) {
        switch (message.what) {
            case ON_CONNECTION: //Gatt链接
                onConnection((BluetoothGatt) message.obj);
                return true;
            case ON_DISCONNECTION: //Gatt断开链接
                onDisconnection();
                return true;
            case ON_SERVICES_DISCOVERED: //发现服务回调
                onServicesDiscovered((BluetoothGatt) message.obj);
                return true;
            case ON_MTU_CHANGED: //MtuSize改变回调
                onMtuChanged((int) message.obj);
                return true;
            case ON_CHARACTERISTIC_READ: //读取特性
                onCharacteristicRead((BluetoothGattCharacteristic) message.obj);
                return true;
            case ON_CHARACTERISTIC_WRITE: //写特性
                onCharacteristicWrite((BluetoothGattCharacteristic) message.obj);
                return true;
            case ON_CHARACTERISTIC_CHANGED: //特性改变回调
                onCharacteristicChanged((Notification) message.obj);
                return true;
            case ON_DESCRIPTOR_WRITE: //描述写入回调
                onDescriptorWrite((BluetoothGattDescriptor) message.obj);
                return true;
        }
        return false;
    }

    // region Handle Successful Callbacks

    @SuppressLint("MissingPermission")
    private void onConnection(@NonNull BluetoothGatt bluetoothGatt) {
        suotaManager.setState(SuotaManager.ManagerState.CONNECTED);
        notifyConnectionStateChanged(CONNECTED);
        Log.d(TAG, "Discover services");
        bluetoothGatt.discoverServices();
    }

    private void onDisconnection() {
        suotaManager.setState(SuotaManager.ManagerState.DISCONNECTED);
        suotaManager.close();
        notifyConnectionStateChanged(DISCONNECTED);
        RingPythonManagement.getRingPythonManagement().sendState = false;
        RingPythonManagement.getRingPythonManagement().setResetGoGusture();
    }

    private void onServicesDiscovered(BluetoothGatt bluetoothGatt) {
        suotaManager.onServicesDiscovered(bluetoothGatt);
    }

    private void onMtuChanged(int mtu) {
        suotaManager.dequeueGattOperation();
    }

    private void onCharacteristicRead(BluetoothGattCharacteristic bluetoothGattCharacteristic) {
        suotaManager.onCharacteristicRead(bluetoothGattCharacteristic);
        suotaManager.dequeueGattOperation();
    }

    private void onCharacteristicWrite(BluetoothGattCharacteristic bluetoothGattCharacteristic) {
        suotaManager.onCharacteristicWrite(bluetoothGattCharacteristic);
        suotaManager.dequeueGattOperation();
    }

    private void onCharacteristicChanged(Notification notification) {
        suotaManager.onCharacteristicChanged(notification.characteristic, notification.value);
    }

    private void onDescriptorWrite(BluetoothGattDescriptor bluetoothGattDescriptor) {
        suotaManager.onDescriptorWrite(bluetoothGattDescriptor);
        suotaManager.dequeueGattOperation();
    }

    /**
     * [ 5a a5 82 0e 64 d4 50 fb 00 26 a4 02 83 00 21 04 09 01 00 ]
     *
     * @param hex
     */
    private void hexArrayModel(String hex) {
        String[] firstHex = hex.split("5a a5 ");

        for (int i = 0; i < firstHex.length; i++) {
            String[] strings = firstHex[i].split(" ");
            StringBuffer stringBuffer1 = new StringBuffer();
            StringBuffer stringBuffer2 = new StringBuffer();
            for (int j = 2; j < strings.length; j++) {
                if (j == 2) {
                    int model = StringUtils.hex16to10String(strings[j]);
                    if (suotaManager != null) {
//                        if (StringUtils.hex16to10String(strings[1]) > 1) {
//                        suotaManager.getSuotaManagerCallback().onModelChange(model);
                        Log.e(TAG + "解析数据", "模式" + model);
//                        }
                    }

                }


            }
        }

    }
    private String hexArrayXandZhongli(String hex) {
        String[] firstHex = hex.split("5a a5 ");

        for (int i = 0; i < firstHex.length; i++) {
            String[] strings = firstHex[i].split(" ");
            StringBuffer stringBuffer1 = new StringBuffer();
            StringBuffer stringBuffer2 = new StringBuffer();
            for (int j = 2; j < strings.length; j++) {
                if (j == 2) {
//                    int power = StringUtils.hex16to10String(strings[j]);
//                    Log.e(TAG + "解析数据", "电量数据" + power);
//                    if (suotaManager != null) {
//                        if (StringUtils.hex16to10String(strings[1]) > 1) {
//                            suotaManager.getSuotaManagerCallback().onPowerChange(power);
//                        }
//                    }

                } else if (j == strings.length - 3) {
                    stringBuffer1.append(StringUtils.hexToDecimal10(strings[j]) + ",");
                } else if (j == strings.length - 2) {
                    stringBuffer1.append(StringUtils.hexToDecimal10(strings[j]) + ",");

                } else if (j == strings.length - 1) {
                    stringBuffer1.append(StringUtils.hexToDecimal10(strings[j]) + "\n");

                } else {
//                    stringBuffer2.append((StringUtils.hex16to10String(strings[j])));
                }

            }
//            if (stringBuffer1.toString().endsWith(",")) {
//                stringBuffer1.deleteCharAt(stringBuffer2.length() - 1);
//            }
//            if (stringBuffer1.toString().endsWith(",")) {
//                stringBuffer1.deleteCharAt(stringBuffer1.length() - 1);
//            }
//            stringBuffer2.append("}");

//            Log.e(TAG + "解析数据", "加速度数据" + stringBuffer1.toString());
//            if (!stringBuffer2.toString().equals("{}")) {
            if (i == firstHex.length - 1) {
//                Log.e(TAG + "解析数据", "加速度数据" + stringBuffer1.toString() + "\n" + " X,Y,Z数据" + stringBuffer2.toString());
//                stringBuffer2.toString() +
                return stringBuffer1.toString();
            }
        }
        return "";
    }

    private String hexArrayData(String hex) {
        String[] firstHex = hex.split("5a a5 ");

        for (int i = 0; i < firstHex.length; i++) {
            String[] strings = firstHex[i].split(" ");
            StringBuffer stringBuffer1 = new StringBuffer();
            StringBuffer stringBuffer2 = new StringBuffer();
            for (int j = 2; j < strings.length; j++) {
                if (j == 2) {
                    int power = StringUtils.hex16to10String(strings[j]);
                    Log.e(TAG + "解析数据", "电量数据" + power);
//                    if (suotaManager != null)
//                        if (StringUtils.hex16to10String(strings[1]) > 1) {
//                            suotaManager.getSuotaManagerCallback().onPowerChange(power);
//                        }

                } else if (j > 2 && j < 9) {
                    stringBuffer1.append(StringUtils.hexToDecima0l(strings[j], strings[j + 1]) + ",");

                    j = j + 1;
                } else if (j >= 9 && j < strings.length - 2) {
                    stringBuffer2.append(StringUtils.hexToDecima0l(strings[j], strings[j + 1]) + ",");
                    j = j + 1;
                } else {
                    stringBuffer2.append((StringUtils.hex16to10String(strings[j])));
                }

            }
            if (stringBuffer2.toString().endsWith(",")) {
                stringBuffer2.deleteCharAt(stringBuffer2.length() - 1);
            }
//            if (stringBuffer1.toString().endsWith(",")) {
//                stringBuffer1.deleteCharAt(stringBuffer1.length() - 1);
//            }
//            stringBuffer2.append("}");

//            Log.e(TAG + "解析数据", "加速度数据" + stringBuffer1.toString());
//            if (!stringBuffer2.toString().equals("{}")) {
            if (i == firstHex.length - 1) {
                Log.e(TAG + "解析数据", "加速度数据" + stringBuffer1.toString() + "\n" + " X,Y,Z数据" + stringBuffer2.toString());
//                stringBuffer2.toString() +
                return stringBuffer1.toString() + stringBuffer2.toString() + "\n";
            }
        }
        return "";
    }

    // endregion
}
